{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "ImportError",
     "evalue": "cannot import name 'SegmenticRoleLabeller' from 'pyltp' (C:\\Users\\Administrator\\Anaconda3\\lib\\site-packages\\pyltp.cp37-win_amd64.pyd)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-8-8a11d268a940>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mre\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mpyvis\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnetwork\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mNetwork\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mpyltp\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mSegmentor\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mPostagger\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParser\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mSegmenticRoleLabeller\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mImportError\u001b[0m: cannot import name 'SegmenticRoleLabeller' from 'pyltp' (C:\\Users\\Administrator\\Anaconda3\\lib\\site-packages\\pyltp.cp37-win_amd64.pyd)"
     ]
    }
   ],
   "source": [
    "import os \n",
    "import re\n",
    "from pyvis.network import Network\n",
    "from pyltp import Segmentor, Postagger, Parser, SegmenticRoleLabeller\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对句子进行语义角色标注\n",
    "def parser_main(sentence):\n",
    "    LTP_DIR = \"./ltp_data_v3.4.0\"  # LTP模型文件路径\n",
    "    # 实例化Segmentor类的对象\n",
    "    segmentor = Segmentor(os.path.join(LTP_DIR, \"cws.model\"))\n",
    "    # 实例化Postagger类的对象\n",
    "    postagger = Postagger(os.path.join(LTP_DIR, \"pos.model\"))\n",
    "    # 实例化Parser类的对象\n",
    "    parser = Parser(os.path.join(LTP_DIR, \"parser.model\"))\n",
    "    # 实例化SemanticRoleLabeler类的对象\n",
    "    labeler = SemanticRoleLabeler(os.path.join(LTP_DIR, \"pisrl_win.model\"))\n",
    "\n",
    "    words = list(segmentor.segment(sentence))  # 分词\n",
    "    postags = list(postagger.postag(words))  # 词性标注\n",
    "    arcs = parser.parse(words, postags)  # 依存句法分析\n",
    "    roles = labeler.label(words, postags, arcs)  # 语义角色标注\n",
    "    roles_dict = {key: {sub_key: [*value] for sub_key, value in sub_data.items()} for key, sub_data in roles.items()}\n",
    "    return words, postags, arcs, roles_dict\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'text' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-10-6eff09f48a67>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mwords\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mpostags\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0marcs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mroles_dict\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparser_main\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtext\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'分词结果'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mwords\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'语义角色标注结果'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mroles_dict\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'text' is not defined"
     ]
    }
   ],
   "source": [
    "words,postags,arcs,roles_dict = parser_main(text)\n",
    "print('分词结果',words)\n",
    "print('语义角色标注结果',roles_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ruler(words, postags, roles_dict, role_index):\n",
    "    v = words[role_index]  # 提取词索引对应的谓词\n",
    "    role_info = roles_dict[role_index]\n",
    "\n",
    "    # 提取施事\n",
    "    s = ''.join([words[word_index] \n",
    "                 for word_index in range(role_info['A0'][0][1], \n",
    "                                         role_info['A0'][1][2] + 1)\n",
    "                 if role_info['A0'][1][0] not in ['w', 'u', 'x']])\n",
    "\n",
    "    # 提取施事\n",
    "    o = ''.join([words[word_index] \n",
    "                 for word_index in range(role_info['A1'][0][1], \n",
    "                                         role_info['A1'][0][2] + 1)\n",
    "                 if role_info['A1'][0][0] not in ['w', 'u', 'x'] and \n",
    "                    words[word_index] not in ['w', 'u', 'x']])\n",
    "\n",
    "    if s and o:\n",
    "        return '1', [s, v, o]  # 返回[施事，谓词，受事]形式的三元组\n",
    "\n",
    "    return '4', []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def triples_main(text):\n",
    "    # 使用正则表达式将文本分割为句子\n",
    "    sentences = [sentence for sentence in re.split(r'[？？！。；；：\\n\\r]', text) if sentence]\n",
    "    svos = []\n",
    "\n",
    "    for index, sentence in enumerate(sentences):\n",
    "        words, postags, arcs, roles_dict = parser_main(sentence)\n",
    "        for index in range(len(postags)):\n",
    "            # 根据语义角色标注提取三元组\n",
    "            if index in roles_dict:\n",
    "                flag, triple = ruler(words, postags, roles_dict, index)\n",
    "                if flag == '1':\n",
    "                    svos.append(triple)\n",
    "\n",
    "    return svos\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'text' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-13-d0af58b3665a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0msvos\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtriples_main\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtext\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"文本的三元组: svos = {0}\"\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msvos\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'text' is not defined"
     ]
    }
   ],
   "source": [
    "svos = triples_main(text)\n",
    "print(\"文本的三元组: svos = {0}\".format(svos))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建语义网络中的节点\n",
    "def create_node(net, subs1, subs2):\n",
    "    if len(subs1) != 0:\n",
    "        for i in range(len(subs1)):\n",
    "            # 调用 add_node() 方法创建节点\n",
    "            net.add_node(i, label=subs1[i], color=\"blue\")\n",
    "\n",
    "    if len(subs2) != 0:\n",
    "        for i in range(len(subs2)):\n",
    "            net.add_node(1000+i, label=subs2[i], color=\"green\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义 create_node_id_dic() 函数，创建节点标签到节点 ID 的映射字典\n",
    "def create_node_id_dic(net):\n",
    "    dic_node_id = {}\n",
    "    for i in net.node_ids:\n",
    "        dic_node_id[str(net.node_map[i][\"label\"])] = i\n",
    "    return dic_node_id\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义 create_network() 函数，调用 Network 类的方法 add_edge()，添加语义网络中节点之间的边\n",
    "def create_network(net, kg_list, node_id_dic):\n",
    "    for m in range(len(kg_list)):\n",
    "        try:\n",
    "            net.add_edge(node_id_dic[kg_list[m][0]],\n",
    "                         node_id_dic[kg_list[m][2]], label=kg_list[m][1], color=\"red\", width=2)\n",
    "        except AttributeError as e:\n",
    "            print(e, m)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Warning: When  cdn_resources is 'local' jupyter notebook has issues displaying graphics on chrome/safari. Use cdn_resources='in_line' or cdn_resources='remote' if you have issues viewing graphics in a notebook.\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'svos' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-17-648de1d8d0e9>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;31m# 从 svos 中提取 sub1 和 sub2\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0msubs1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msublist\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0msublist\u001b[0m \u001b[1;32min\u001b[0m \u001b[0msvos\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# 提取所有 subject\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      6\u001b[0m \u001b[0msubs2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msublist\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0msublist\u001b[0m \u001b[1;32min\u001b[0m \u001b[0msvos\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# 提取所有 object\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'svos' is not defined"
     ]
    }
   ],
   "source": [
    "# 实例化 Network 类的对象 net\n",
    "net = Network(notebook=True, directed=True)\n",
    "\n",
    "# 从 svos 中提取 sub1 和 sub2\n",
    "subs1 = list(set(sublist[0] for sublist in svos))  # 提取所有 subject\n",
    "subs2 = list(set(sublist[2] for sublist in svos))  # 提取所有 object\n",
    "\n",
    "# 调用 create_node() 函数创建语义网络的节点\n",
    "create_node(net, subs1, subs2)\n",
    "\n",
    "# 调用 create_node_id_dic() 函数创建节点标签到节点 ID 的映射字典\n",
    "dic_node_id = create_node_id_dic(net)\n",
    "\n",
    "# 调用 create_network() 函数添加语义网络中节点之间的边\n",
    "create_network(net, svos, dic_node_id)\n",
    "\n",
    "# 显示语义网络\n",
    "net.show(\"my_network.html\")  # 显示语义网络\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_similar_semantics(net, node_id_dic, target_node):\n",
    "    # 查找目标节点的 ID\n",
    "    target_node_id = node_id_dic[target_node]\n",
    "    \n",
    "    # 获取目标节点的所有相邻节点\n",
    "    adjacent_nodes = net.neighbors(target_node_id)\n",
    "    \n",
    "    # 使用逆字典将相邻节点的 ID 转换为节点标签\n",
    "    similar_semantics = [node_id_dic_inverse[node_id] for node_id in adjacent_nodes]\n",
    "    \n",
    "    return similar_semantics\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'dic_node_id' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-19-229b7e051f85>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mnode_id_dic_inverse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mk\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mk\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mv\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mdic_node_id\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;31m# 查找与目标词“苏轼”语义相关的词\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0msimilar\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfind_similar_semantics\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnet\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdic_node_id\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'苏轼'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"与目标词'苏轼'语义相关的词：\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msimilar\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'dic_node_id' is not defined"
     ]
    }
   ],
   "source": [
    "node_id_dic_inverse = {v: k for k, v in dic_node_id.items()}\n",
    "\n",
    "# 查找与目标词“苏轼”语义相关的词\n",
    "similar = find_similar_semantics(net, dic_node_id, '苏轼')\n",
    "print(\"与目标词'苏轼'语义相关的词：\", similar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
